/*
 * Copyright 2012 Marsrutai.lt
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package lt.marsrutai.mobile.android.fragment;

import java.util.Collections;
import java.util.List;

import lt.marsrutai.mobile.android.AppContext;
import lt.marsrutai.mobile.android.R;
import lt.marsrutai.mobile.android.activity.intent.NearestRoutesIntentHolder;
import lt.marsrutai.mobile.android.activity.intent.StopSearchIntentHolder;
import lt.marsrutai.mobile.android.activity.intent.TaskIntentHolder;
import lt.marsrutai.mobile.android.adapter.StopIndexedAdapter;
import lt.marsrutai.mobile.android.bean.StopSearchCriteria;
import lt.marsrutai.mobile.android.content.StopSearchRecentSuggestionsProvider;
import lt.marsrutai.mobile.android.exception.DataAccessException;
import lt.marsrutai.mobile.android.fragment.task.GetLocationTaskDialogFragment;
import lt.marsrutai.mobile.android.fragment.task.TaskDialogFragment;
import lt.marsrutai.mobile.android.manager.ActivityManager;
import lt.marsrutai.mobile.android.manager.StopSearchPreferenceManager;
import lt.marsrutai.mobile.android.model.Stop;
import lt.marsrutai.mobile.android.task.GetLocationTask;
import lt.marsrutai.mobile.android.util.PreferenceUtils;
import lt.marsrutai.mobile.android.util.StringUtils;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TextView;

import com.actionbarsherlock.app.SherlockListFragment;

public class StopSearchFragment extends SherlockListFragment {

    private static final String GET_LOCATION_TASK_FRAGMENT_TAG = "getLocationTask";
    
    private FragmentManager fragmentManager;
    private ActivityManager manager;

    private List<Stop> stops;
    private StopIndexedAdapter adapter;

    private String scopeFolder;
    private String scopeName;

    private BroadcastReceiver locationReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            TaskIntentHolder holder = new TaskIntentHolder(intent);

            switch (holder.getStatus()) {
                case Activity.RESULT_OK:
                    final Location result = holder.getResult();
                    
                    new Thread(new Runnable() {
                        
                        @Override
                        public void run() {
                            getClosestStops(result);
                        }
                    }).start();
                    break;
                case GetLocationTask.RESULT_LOCATION_NOT_RESOLVED:
                    TextView emptyText = (TextView) getActivity().findViewById(android.R.id.empty);
                    emptyText.setText(holder.getResultMessage());
                    break;
            }
        }
    };

    @Override
    public void onResume() {
        super.onResume();
        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(locationReceiver, new IntentFilter(GetLocationTask.BROADCAST_ACTION));

        // Check whether the worker fragment has been retained
        TaskDialogFragment<?, ?, ?> taskFragment = (TaskDialogFragment<?, ?, ?>) fragmentManager.findFragmentByTag(GET_LOCATION_TASK_FRAGMENT_TAG);

        // show downloading indicator - it will be dismissed if no downloads are in progress
        manager.showDownloadLoadingBar();
        
        // Start downloading only if we don't have any scopes, and task fragments has not been retained
        if (!TaskDialogFragment.isActive(taskFragment)) {
            if (stops == null) {
                downloadData();
            }
            else {
                fillAdapter();
                manager.dismissDownloadLoadingBar();
            }
        }
    }

    @Override
    public void onPause() {
        super.onPause();

        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(locationReceiver);
    }
    
    @Override
    public void onStart() {
        super.onStart();
        
        // Activity visible - start listening for location updates
        AppContext.getLocationProvider().start();
    }

    @Override
    public void onStop() {
        super.onStart();
        
        // Activity hidden - stop listening for location updates
        AppContext.getLocationProvider().stop();
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /*
         * Data download starts before onStart() is called, therefore we need
         * to start listening for location updates here
         */
        AppContext.getLocationProvider().start();
        
        restoreState(savedInstanceState);

        fragmentManager = getFragmentManager();
        manager = new ActivityManager(getActivity());
        adapter = new StopIndexedAdapter(getActivity(), bundleState());

        setListAdapter(adapter);
    }
    
    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putAll(bundleState());
        
        super.onSaveInstanceState(outState);
    }

    protected Bundle bundleState() {
        StopSearchIntentHolder intentHolder = new StopSearchIntentHolder(new Bundle());
        intentHolder.setScopeFolder(scopeFolder);
        intentHolder.setScopeName(scopeName);
        intentHolder.setStops(stops);
        
        return intentHolder.getIntent().getExtras();
    }

    private void restoreState(Bundle bundle) {
        if (bundle == null) {
            bundle = getArguments();
        }
        
        StopSearchIntentHolder intentHolder = new StopSearchIntentHolder(bundle);
        scopeFolder = intentHolder.getScopeFolder();
        scopeName = intentHolder.getScopeName();
        stops = intentHolder.getStops();
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.list_fragment, null);
        TextView emptyText = (TextView) view.findViewById(android.R.id.empty);
        emptyText.setText(R.string.stop_search_not_found);

        return view;
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        sendItemData(position);
    }

    private StopSearchIntentHolder getIntentHolder() {
        return new StopSearchIntentHolder(getArguments());
    }

    private void sendItemData(int i) {
        Stop stop = adapter.getItem(i);
        NearestRoutesIntentHolder intentHolder = new NearestRoutesIntentHolder(getActivity());
        intentHolder.setScopeFolder(scopeFolder);
        intentHolder.setStopName(stop.getName());
        intentHolder.setStopFullName(stop.getFullName());
        intentHolder.setStopId(stop.getId());
        intentHolder.setStopDirectionName(stop.getDirectionName());
        startActivity(intentHolder.getIntent());
    }

    private void downloadData() {
        String constraint = getIntentHolder().getQuery();
        if (StringUtils.equals(constraint, StopSearchRecentSuggestionsProvider.QUERY_CLOSEST_STOPS)) {
            // Be sure that we're not starting the download again, if the worker fragment is already created
            TaskDialogFragment<?, ?, ?> taskFragment = (TaskDialogFragment<?, ?, ?>) fragmentManager.findFragmentByTag(GET_LOCATION_TASK_FRAGMENT_TAG);
            if (!TaskDialogFragment.isActive(taskFragment)) {
                TaskDialogFragment.download(fragmentManager, 
                        GetLocationTaskDialogFragment.class, GET_LOCATION_TASK_FRAGMENT_TAG);
            }
        }
        else {
            new Thread(new Runnable() {
                
                @Override
                public void run() {
                    getStops();
                }
            }).start();
        }
    }

    private void getClosestStops(Location location) {
        try {
            if (location != null) {
                int searchRadius = PreferenceUtils.<Integer> getPreferenceValue(getActivity(),
                        StopSearchPreferenceManager.KEY_NEARBY_STOP_RADIUS);
                stops = AppContext.getDataService().getStops(scopeFolder, true, null, location.getLatitude(), location.getLongitude(),
                        (double) searchRadius / 1000);
            }
            else {
                stops = Collections.emptyList();
            }
        }
        catch (DataAccessException e) {
            manager.runOnUiThread(manager.errorRes);
            return;
        }
        manager.runOnUiThread(returnRes);
    }

    private void getStops() {
        try {
            String constraint = getIntentHolder().getQuery();

            stops = AppContext.getDataService().getStops(scopeFolder, true, constraint, null, null, null);
        }
        catch (DataAccessException e) {
            manager.runOnUiThread(manager.errorRes);
            return;
        }
        manager.runOnUiThread(returnRes);
    }

    private final Runnable returnRes = new Runnable() {

        @Override
        public void run() {
            fillAdapter();

            manager.dismissDownloadLoadingBar();
        }
    };

    protected void fillAdapter() {
        if (stops != null && stops.size() > 0) {
            for (int i = 0; i < stops.size(); i++) {
                adapter.add(stops.get(i));
            }
        }

        adapter.setOriginalValues(stops);
        adapter.initIndexer();

        // Perform highlighting
        StopSearchCriteria criteria = new StopSearchCriteria();
        criteria.setQuery(getIntentHolder().getQuery());
        filterResults(criteria);
    }

    private void filterResults(StopSearchCriteria criteria) {
        adapter.setSearchCriteria(criteria);
        // No constraint is necessary - filter should use provided search
        // criteria
        adapter.getFilter().filter(null);
    }

    public void searchAgain(String query) {
        getArguments().putString(StopSearchIntentHolder.QUERY, query);
        adapter.clear();
        downloadData();
    }
}
